window.onerror = (event, source, line, col, err) => {}
// 在这个例子里，虽然我们并没有为 onerror 的各个参数声明类型，但是它们也已经获得了正确的类型。

// 当然你肯定能猜到，这是因为 onerror 的类型声明已经内置了：
interface Handler {
  // 简化
  onerror: OnErrorEventHandlerNonNull
}
interface OnErrorEventHandlerNonNull {
  (event: Event | string, source?: string, lineno?: number, colno?: number, error?: Error): any
}

type CustomHandler = (name: string, age: number) => boolean
// 也推导出了参数类型
const handler: CustomHandler = (arg1, arg2) => {
  return true
}

//除了参数类型，返回值类型同样会纳入管控：
declare const struct: {
  handler: CustomHandler
}
// 不能将类型“void”分配给类型“boolean”。
struct.handler = (name, age) => {
  // 没有这个会报错
  return true
}

//在上下文类型中，我们实现的表达式可以只使用更少的参数，而不能使用更多，这还是因为上下文类型基于位置的匹配，一旦参数个数超过定义的数量，那就没法进行匹配了。
// 正常
window.onerror = (event) => {}
// 报错
// window.onerror = (event, source, line, col, err, extra) => {}

//上下文类型也可以进行”嵌套“情况下的类型推导，如以下这个例子：
declare let func: (raw: number) => (input: string) => any
// raw → number
func = (raw) => {
  // input → string
  return (input) => {}
}

//在某些情况下，上下文类型的推导能力也会失效，比如这里我们使用一个由函数类型组成的联合类型：
class Foo {
  foo!: number
}
class Bar extends Foo {
  bar!: number
}

let f1: { (input: Foo): void } | { (input: Bar): void }

// 参数“input”隐式具有“any”类型。
// f1 = (input) => {}

// 你可以直接使用一个联合类型参数的函数签名：

let f2: { (input: Foo | Bar): void }

// Foo | Bar
f2 = (input) => {} // any

//而如果联合类型中将这两个类型再嵌套一层，此时上下文类型反而正常了：
let f3: { (raw: number): (input: Foo) => void } | { (raw: number): (input: Bar) => void }

f3 = (raw) => {
  return (input) => {}
}
